package com.hihuzi.lambda.util;

import com.hihuzi.lambda.annotation.LFunction;
import com.hihuzi.lambda.annotation.SupplierPlus;
import com.hihuzi.lambda.entity.SerializedLambda;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;

public class LambdaUtil {
    /**
     * 获取类的对象方法-不带形参（序列化方式）
     *
     * @param function
     * @param <T>
     * @return
     */
    public static <T> SerializedLambda lffSimple(LFunction<T, ?> function) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
        try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
            oos.writeObject(function);
            oos.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        try (ObjectInputStream inputStream = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())) {
            Class<?> clazz;

            @Override
            protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
                clazz = super.resolveClass(desc);
                return clazz == java.lang.invoke.SerializedLambda.class ? SerializedLambda.class : clazz;
            }
        }) {
            return (SerializedLambda) inputStream.readObject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 获取类的对象方法-带形参（序列化方式）
     *
     * @param function
     * @param <T>
     * @return
     */
    public static <T, R> java.lang.invoke.SerializedLambda SPSimple(SupplierPlus<T, R> function) {
        Method method = function.getClass().getDeclaredMethods()[1];
        method.setAccessible(true);
        try {
            return (java.lang.invoke.SerializedLambda) method.invoke(function);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    public static <T, R> Object SPSimplePlus(SupplierPlus<T, R>[] supplierPluses) {
        return Arrays.stream(supplierPluses).distinct().map(supplierPlus -> {
            Method method = supplierPlus.getClass().getDeclaredMethods()[2];
            method.setAccessible(true);
            try {
                return ((java.lang.invoke.SerializedLambda) method.invoke(supplierPlus)).getImplMethodName();
            } catch (IllegalAccessException | InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        }).collect(Collectors.toList());

    }
}

